package com.jingxuan.util;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import lombok.Data;
import lombok.Builder;
import lombok.Setter;
import lombok.AccessLevel;

/**
 * 排行榜算法工具类
 * 包含推荐榜、性价比榜、新品榜三个排行榜的算法实现
 */
public class RankAlgorithm {
    
    // ==================== 特征解析 ====================
    
    /**
     * 解析好评率
     * 从"4.8\n88VIP好评率98%"中提取：评分4.8, 好评率98%
     */
    public static GoodRateInfo parseGoodRate(String description) {
        if (description == null || description.isEmpty()) {
            return GoodRateInfo.builder()
                    .rating(0.0)
                    .goodRate(0.0)
                    .build();
        }
        
        double rating = 0.0;
        double goodRate = 0.0;
        
        // 提取评分：匹配 "4.8" 或 "4.8分" 等格式
        Pattern ratingPattern = Pattern.compile("(\\d+\\.?\\d*)\\s*分?");
        Matcher ratingMatcher = ratingPattern.matcher(description);
        if (ratingMatcher.find()) {
            try {
                rating = Double.parseDouble(ratingMatcher.group(1));
            } catch (NumberFormatException e) {
                // 忽略解析错误
            }
        }
        
        // 提取好评率：匹配 "好评率98%" 或 "98%好评率" 等格式
        Pattern ratePattern = Pattern.compile("好评率\\s*(\\d+\\.?\\d*)%|(\\d+\\.?\\d*)%\\s*好评率");
        Matcher rateMatcher = ratePattern.matcher(description);
        if (rateMatcher.find()) {
            try {
                String rateStr = rateMatcher.group(1) != null ? rateMatcher.group(1) : rateMatcher.group(2);
                goodRate = Double.parseDouble(rateStr);
            } catch (NumberFormatException e) {
                // 忽略解析错误
            }
        }
        
        return GoodRateInfo.builder()
                .rating(rating)
                .goodRate(goodRate)
                .build();
    }
    
    /**
     * 解析加购人数
     * 从"超2万人加购"中提取：20000
     * 从"超3万人加购"中提取：30000
     */
    public static Integer parseCartCount(String description) {
        if (description == null || description.isEmpty()) {
            return 0;
        }
        
        // 匹配 "超X万人加购" 或 "超X千人加购" 等格式
        Pattern pattern = Pattern.compile("超\\s*(\\d+)\\s*([万千])\\s*人加购");
        Matcher matcher = pattern.matcher(description);
        
        if (matcher.find()) {
            try {
                int number = Integer.parseInt(matcher.group(1));
                String unit = matcher.group(2);
                
                if ("万".equals(unit)) {
                    return number * 10000;
                } else if ("千".equals(unit)) {
                    return number * 1000;
                }
            } catch (NumberFormatException e) {
                // 忽略解析错误
            }
        }
        
        return 0;
    }
    
    /**
     * 解析回头客数
     * 从"超2千回头客"中提取：2000
     * 从"超5千回头客"中提取：5000
     */
    public static Integer parseReturnCustomerCount(String description) {
        if (description == null || description.isEmpty()) {
            return 0;
        }
        
        // 匹配 "超X千回头客" 或 "超X万回头客" 等格式
        Pattern pattern = Pattern.compile("超\\s*(\\d+)\\s*([万千])\\s*回头客");
        Matcher matcher = pattern.matcher(description);
        
        if (matcher.find()) {
            try {
                int number = Integer.parseInt(matcher.group(1));
                String unit = matcher.group(2);
                
                if ("万".equals(unit)) {
                    return number * 10000;
                } else if ("千".equals(unit)) {
                    return number * 1000;
                }
            } catch (NumberFormatException e) {
                // 忽略解析错误
            }
        }
        
        return 0;
    }
    
    /**
     * 解析发货速度
     */
    public static String parseDeliverySpeed(String description) {
        if (description == null || description.isEmpty()) {
            return null;
        }
        
        // 匹配发货速度相关描述
        Pattern pattern = Pattern.compile("(\\d+)\\s*小时.*发货|(\\d+)\\s*天.*发货|发货.*(\\d+)\\s*小时|发货.*(\\d+)\\s*天");
        Matcher matcher = pattern.matcher(description);
        
        if (matcher.find()) {
            return matcher.group(0);
        }
        
        return null;
    }
    
    /**
     * 解析客服响应时间
     */
    public static String parseServiceResponseTime(String description) {
        if (description == null || description.isEmpty()) {
            return null;
        }
        
        // 匹配客服响应时间相关描述
        Pattern pattern = Pattern.compile("客服.*(\\d+)\\s*分钟|(\\d+)\\s*分钟.*响应|响应.*(\\d+)\\s*分钟");
        Matcher matcher = pattern.matcher(description);
        
        if (matcher.find()) {
            return matcher.group(0);
        }
        
        return null;
    }
    
    // ==================== 情感分析 ====================
    
    private static final Set<String> POSITIVE_WORDS = new HashSet<>(Arrays.asList(
            "好", "棒", "满意", "推荐", "舒服"
    ));
    
    private static final Set<String> MEDIUM_POSITIVE_WORDS = new HashSet<>(Arrays.asList(
            "不错", "可以", "合适"
    ));
    
    private static final Map<String, Double> INTENSITY_WORDS = new HashMap<>();
    static {
        INTENSITY_WORDS.put("很", 1.2);
        INTENSITY_WORDS.put("非常", 1.5);
        INTENSITY_WORDS.put("特别", 1.5);
        INTENSITY_WORDS.put("极其", 2.0);
        INTENSITY_WORDS.put("超级", 1.8);
        INTENSITY_WORDS.put("十分", 1.5);
    }
    
    /**
     * 计算评论情感正向度
     * @param comments 评论列表
     * @return 情感分（0-30）
     */
    public static double calculateSentimentScore(List<CommentInfo> comments) {
        if (comments == null || comments.isEmpty()) {
            return 15.0; // 默认中性分
        }
        
        double totalScore = 0.0;
        int totalComments = comments.size();
        
        for (CommentInfo comment : comments) {
            if (comment.getContent() == null) {
                continue;
            }
            
            String content = comment.getContent();
            double commentScore = 0.0;
            
            // 强正向词 +6分
            for (String word : POSITIVE_WORDS) {
                if (content.contains(word)) {
                    commentScore += 6;
                }
            }
            
            // 中正向词 +4分
            for (String word : MEDIUM_POSITIVE_WORDS) {
                if (content.contains(word)) {
                    commentScore += 4;
                }
            }
            
            totalScore += commentScore;
        }
        
        double avgScore = totalScore / totalComments;
        return Math.min(30.0, avgScore);
    }
    
    /**
     * 计算评论详细度
     * @param comments 评论列表
     * @return 评论详细度分（0-30）
     */
    public static double calculateCommentDetailScore(List<CommentInfo> comments) {
        if (comments == null || comments.isEmpty()) {
            return 0.0;
        }
        
        double totalScore = 0.0;
        for (CommentInfo comment : comments) {
            if (comment.getContent() != null) {
                int length = comment.getContent().length();
                if (length > 50) {
                    totalScore += 30;
                } else if (length >= 20) {
                    totalScore += 20;
                } else {
                    totalScore += 10;
                }
            }
        }
        
        return totalScore / comments.size();
    }

    /**
     * 计算信息价值度
     * @param comments 评论列表
     * @return 信息价值度分（0-30）
     */
    public static double calculateInformationValueScore(List<CommentInfo> comments) {
        if (comments == null || comments.isEmpty()) {
            return 0.0;
        }

        double totalScore = 0.0;
        Set<String> dimensionKeywords = new HashSet<>(Arrays.asList("合适", "偏大", "偏小"));
        Set<String> materialKeywords = new HashSet<>(Arrays.asList("柔软", "舒服", "厚实"));
        Set<String> sceneKeywords = new HashSet<>(Arrays.asList("睡觉", "居家", "外穿"));

        for (CommentInfo comment : comments) {
            if (comment.getContent() == null) continue;
            String content = comment.getContent();
            double commentScore = 0.0;

            for (String word : dimensionKeywords) {
                if (content.contains(word)) { commentScore += 10; break; }
            }
            for (String word : materialKeywords) {
                if (content.contains(word)) { commentScore += 10; break; }
            }
            for (String word : sceneKeywords) {
                if (content.contains(word)) { commentScore += 10; break; }
            }
            totalScore += Math.min(30, commentScore);
        }

        return totalScore / comments.size();
    }
    
    // ==================== 推荐榜算法 ====================
    
    /**
     * 计算价格维度评分（0-100分）
     * 价格评分 = 30 + 70 × (最高价 - 当前价) ÷ (最高价 - 最低价)
     */
    public static double calculatePriceScore(BigDecimal currentPrice, BigDecimal minPrice, BigDecimal maxPrice) {
        if (currentPrice == null || minPrice == null || maxPrice == null) {
            return 30.0; // 默认基础分
        }
        
        double current = currentPrice.doubleValue();
        double min = minPrice.doubleValue();
        double max = maxPrice.doubleValue();
        
        if (max <= min) {
            return 30.0; // 价格相同，返回基础分
        }
        
        double score = 30.0 + 70.0 * (max - current) / (max - min);
        return Math.max(0, Math.min(100, score));
    }
    
    /**
     * 计算口碑维度评分（0-100分）
     * 口碑评分 = 0.6 × 好评率分 + 0.4 × 评论质量分
     * 评论质量分 = 40 × 评论详细度 + 30 × 情感正向度 + 30 × 信息价值度
     */
    public static double calculateReputationScore(double goodRate, double detailScore, double sentimentScore, double infoValueScore) {
        double qualityScore = 40.0 * (detailScore / 30.0) + 30.0 * (sentimentScore / 30.0) + 30.0 * (infoValueScore / 30.0);
        // Normalize quality score to 0-100 roughly (detail max 30, sentiment max 30, info max 30 -> sum approx 90-100 scaled)
        // Actually the formula implies weights relative to max possible score.
        // Let's assume input scores are already absolute values as per requirement description.
        // The prompt says:
        // 评论详细度：max 30
        // 情感正向度：max 30
        // 信息价值度：max 30 (implied from +10 * 3 categories)
        // So sum is max 90. Let's scale it to 100.
        double rawQualityScore = detailScore + sentimentScore + infoValueScore;
        double normalizedQualityScore = (rawQualityScore / 90.0) * 100.0;

        return 0.6 * goodRate + 0.4 * normalizedQualityScore;
    }
    
    /**
     * 计算热度维度评分（0-100分）
     * 热度评分 = 0.4 × 评论数量分 + 0.3 × 加购热度分 + 0.3 × 回头客分
     */
    public static double calculateHeatScore(int commentCount, int cartCount, int returnCustomerCount) {
        // 评论数量分 = min(100, 评论数量 × 5)
        double commentCountScore = Math.min(100, commentCount * 5.0);
        
        // 加购热度分 = min(100, 加购人数 ÷ 200)
        double cartCountScore = Math.min(100, cartCount / 200.0);
        
        // 回头客分 = min(100, 回头客数 ÷ 20)
        double returnCustomerScore = Math.min(100, returnCustomerCount / 20.0);
        
        return 0.4 * commentCountScore + 0.3 * cartCountScore + 0.3 * returnCustomerScore;
    }
    
    /**
     * 计算时效维度评分（0-100分）
     * 时效评分 = 0.7 × 评论时效分 + 0.3 × 商品新鲜度分
     */
    public static double calculateTimelinessScore(LocalDateTime lastCommentTime, LocalDateTime now, 
                                                   String productName, String description) {
        // 评论时效分（权重70%）
        double commentTimelinessScore = 0.0;
        if (lastCommentTime != null && now != null) {
            long days = ChronoUnit.DAYS.between(lastCommentTime, now);
            // 时效衰减：max(0, 100 - 天数差 × 8)
            commentTimelinessScore = Math.max(0, 100 - days * 8.0);
        }
        
        // 商品新鲜度分（权重30%）
        double freshnessScore = calculateProductFreshnessScore(productName, description);
        
        return 0.7 * commentTimelinessScore + 0.3 * freshnessScore;
    }
    
    /**
     * 计算商品新鲜度分
     * 从商品名称和描述中识别新品关键词
     */
    private static double calculateProductFreshnessScore(String productName, String description) {
        double score = 0.0;
        String text = (productName != null ? productName : "") + " " + (description != null ? description : "");
        
        // 强关键词：新款、2025新款、新品、最新（+60分）
        String[] strongKeywords = {"新款", "2025新款", "新品", "最新"};
        for (String keyword : strongKeywords) {
            if (text.contains(keyword)) {
                return 60.0; // Found strong keyword, return immediately or take max? Description says "+60分", likely categorical.
            }
        }
        
        // 中关键词：新、同款（+40分）
        String[] mediumKeywords = {"新", "同款"};
        for (String keyword : mediumKeywords) {
            if (text.contains(keyword)) {
                return 40.0;
            }
        }
        
        // 弱关键词：冬季、秋冬（+20分）
        String[] weakKeywords = {"冬季", "秋冬"};
        for (String keyword : weakKeywords) {
            if (text.contains(keyword)) {
                return 20.0;
            }
        }
        
        return 0.0;
    }
    
    /**
     * 计算推荐榜综合得分
     * 综合评分 = 0.25×价格评分 + 0.35×口碑评分 + 0.25×热度评分 + 0.15×时效评分
     */
    public static double calculateRecommendScore(double priceScore, double reputationScore, 
                                                  double heatScore, double timelinessScore) {
        return 0.25 * priceScore + 0.35 * reputationScore + 0.25 * heatScore + 0.15 * timelinessScore;
    }
    
    // ==================== 性价比榜算法 ====================
    
    /**
     * 计算品牌信誉分
     */
    public static double calculateBrandScore(String productName) {
        if (productName == null) {
            return 70.0; // 默认分
        }
        
        String name = productName.toLowerCase();
        if (name.contains("蕉内")) {
            return 90.0;
        } else if (name.contains("有棵树")) {
            return 85.0;
        } else if (name.contains("都市丽人")) {
            return 80.0;
        } else if (name.contains("in blue")) {
            return 75.0;
        } else {
            return 70.0;
        }
    }
    
    /**
     * 计算质量分
     * 质量分 = 0.6×口碑评分 + 0.4×品牌信誉分
     */
    public static double calculateQualityScore(double reputationScore, double brandScore) {
        return 0.6 * reputationScore + 0.4 * brandScore;
    }
    
    /**
     * 计算基础性价比
     * 基础性价比 = 质量分 ÷ 价格 × 1000
     */
    public static double calculateBaseValueScore(double qualityScore, BigDecimal price) {
        if (price == null || price.doubleValue() <= 0) {
            return 0.0;
        }
        
        return qualityScore / price.doubleValue() * 1000.0;
    }
    
    /**
     * 计算价值验证分
     * @param comments 评论列表
     * @param returnCustomerCount 回头客数
     * @param cartCount 加购人数
     * @return 价值验证分（0-100）
     */
    public static double calculateValueVerificationScore(List<CommentInfo> comments, 
                                                          int returnCustomerCount, int cartCount) {
        // 评论验证分（权重50%）
        double commentVerificationScore = calculateCommentVerificationScore(comments);
        
        // 用户行为验证（权重30%）
        double userBehaviorScore = calculateUserBehaviorScore(returnCustomerCount, cartCount);
        
        // 风险控制分（权重20%）
        double riskControlScore = calculateRiskControlScore(comments);
        
        return 0.5 * commentVerificationScore + 0.3 * userBehaviorScore + 0.2 * riskControlScore;
    }
    
    /**
     * 计算评论验证分
     */
    private static double calculateCommentVerificationScore(List<CommentInfo> comments) {
        if (comments == null || comments.isEmpty()) {
            return 0.0;
        }
        
        Set<String> verificationKeywords = new HashSet<>(Arrays.asList(
                "值", "划算", "性价比", "物超所值", "推荐购买"
        ));
        
        int keywordCount = 0;
        for (CommentInfo comment : comments) {
            if (comment.getContent() != null) {
                for (String keyword : verificationKeywords) {
                    if (comment.getContent().contains(keyword)) {
                        keywordCount++;
                        break; // 每个评论只计算一次
                    }
                }
            }
        }
        
        // 每个关键词出现一次加10分，最高50分
        return Math.min(50, keywordCount * 10);
    }
    
    /**
     * 计算用户行为分
     */
    private static double calculateUserBehaviorScore(int returnCustomerCount, int cartCount) {
        if (cartCount == 0) {
            return 0.0;
        }
        
        // 回头客比例 = 回头客数 ÷ 加购人数
        double returnRate = (double) returnCustomerCount / cartCount;
        
        // 用户行为分 = min(100, 回头客比例 × 1000)
        return Math.min(100, returnRate * 1000);
    }
    
    /**
     * 计算风险控制分
     */
    private static double calculateRiskControlScore(List<CommentInfo> comments) {
        if (comments == null || comments.isEmpty()) {
            return 100.0; // 没有评论，默认满分
        }
        
        Set<String> riskKeywords = new HashSet<>(Arrays.asList(
                "偏大", "掉毛", "起球", "褪色", "缩水"
        ));
        
        int riskCount = 0;
        for (CommentInfo comment : comments) {
            if (comment.getContent() != null) {
                for (String keyword : riskKeywords) {
                    if (comment.getContent().contains(keyword)) {
                        riskCount++;
                        break; // 每个评论只计算一次
                    }
                }
            }
        }
        
        // 每个风险词出现一次减15分，最低0分
        double score = 100.0 - riskCount * 15.0;
        return Math.max(0, score);
    }
    
    /**
     * 计算最终性价比得分
     * 性价比得分 = 基础性价比 × (0.5 + 0.3×用户行为分/100 + 0.2×风险控制分/100)
     */
    public static double calculateFinalValueScore(double baseValueScore, double valueVerificationScore) {
        // 将价值验证分拆分为用户行为分和风险控制分（简化处理）
        double userBehaviorRatio = valueVerificationScore / 100.0;
        double riskControlRatio = valueVerificationScore / 100.0;
        
        return baseValueScore * (0.5 + 0.3 * userBehaviorRatio + 0.2 * riskControlRatio);
    }
    
    // ==================== 新品榜算法 ====================
    
    /**
     * 计算新品识别评分
     * 新品识别分 = 0.6×时间维度 + 0.4×文本维度
     */
    public static double calculateNewProductScore(List<CommentInfo> comments, LocalDateTime now,
                                                    String productName, String description) {
        // 时间维度（权重60%）
        double timeDimensionScore = calculateTimeDimensionScore(comments, now);
        
        // 文本维度（权重40%）
        double textDimensionScore = calculateTextDimensionScore(productName, description);
        
        return 0.6 * timeDimensionScore + 0.4 * textDimensionScore;
    }
    
    /**
     * 计算时间维度分
     */
    private static double calculateTimeDimensionScore(List<CommentInfo> comments, LocalDateTime now) {
        if (comments == null || comments.isEmpty() || now == null) {
            return 0.0;
        }
        
        // 计算评论时间集中度
        List<LocalDateTime> commentTimes = comments.stream()
                .map(CommentInfo::getPublishDate)
                .filter(Objects::nonNull)
                .sorted()
                .collect(Collectors.toList());
        
        if (commentTimes.isEmpty()) {
            return 0.0;
        }
        
        // 计算时间方差
        double mean = commentTimes.stream()
                .mapToLong(time -> ChronoUnit.DAYS.between(commentTimes.get(0), time))
                .average()
                .orElse(0.0);
        
        double variance = commentTimes.stream()
                .mapToDouble(time -> {
                    long days = ChronoUnit.DAYS.between(commentTimes.get(0), time);
                    return Math.pow(days - mean, 2);
                })
                .average()
                .orElse(0.0);
        
        // 时间集中度分 = 100 × (1 - min(1, 时间方差/30))
        double timeConcentrationScore = 100.0 * (1 - Math.min(1, variance / 30.0));
        
        // 最新评论时效
        LocalDateTime latestComment = commentTimes.get(commentTimes.size() - 1);
        long daysSinceLatest = ChronoUnit.DAYS.between(latestComment, now);
        double timelinessScore = 100.0 * Math.exp(-0.15 * daysSinceLatest);
        
        return (timeConcentrationScore + timelinessScore) / 2.0;
    }
    
    /**
     * 计算文本维度分
     */
    private static double calculateTextDimensionScore(String productName, String description) {
        double score = 0.0;
        String text = (productName != null ? productName : "") + " " + (description != null ? description : "");
        
        // 强关键词：新款、2025新款、新品、最新（每个+25分）
        String[] strongKeywords = {"新款", "2025新款", "新品", "最新"};
        for (String keyword : strongKeywords) {
            if (text.contains(keyword)) {
                score += 25;
            }
        }
        
        // 中关键词：新、同款、代言人同款（每个+15分）
        String[] mediumKeywords = {"新", "同款", "代言人同款"};
        for (String keyword : mediumKeywords) {
            if (text.contains(keyword)) {
                score += 15;
            }
        }
        
        // 弱关键词：冬季、秋冬、春秋（每个+5分）
        String[] weakKeywords = {"冬季", "秋冬", "春秋"};
        for (String keyword : weakKeywords) {
            if (text.contains(keyword)) {
                score += 5;
            }
        }
        
        return Math.min(100, score);
    }
    
    /**
     * 计算热力增长评分
     * 热力增长分 = 0.5×评论增长势头 + 0.3×用户关注度 + 0.2×社交传播力
     */
    public static double calculateHeatGrowthScore(List<CommentInfo> comments, LocalDateTime now,
                                                    int cartCount, BigDecimal price) {
        // 评论增长势头（权重50%）
        double growthMomentumScore = calculateGrowthMomentumScore(comments, now);
        
        // 用户关注度（权重30%）
        double userAttentionScore = calculateUserAttentionScore(cartCount, price);
        
        // 社交传播力（权重20%）
        double socialSpreadScore = calculateSocialSpreadScore(comments);
        
        return 0.5 * growthMomentumScore + 0.3 * userAttentionScore + 0.2 * socialSpreadScore;
    }
    
    /**
     * 计算评论增长势头分
     */
    private static double calculateGrowthMomentumScore(List<CommentInfo> comments, LocalDateTime now) {
        if (comments == null || comments.isEmpty() || now == null) {
            return 0.0;
        }
        
        // 近7天评论数
        long recent7DaysCount = comments.stream()
                .filter(comment -> {
                    if (comment.getPublishDate() == null) {
                        return false;
                    }
                    long days = ChronoUnit.DAYS.between(comment.getPublishDate(), now);
                    return days <= 7;
                })
                .count();
        
        // 近期评论占比 = 近7天评论数 ÷ 总评论数
        double recentRatio = (double) recent7DaysCount / comments.size();
        
        // 增长势头分 = 近期评论占比 × 100
        return recentRatio * 100.0;
    }
    
    /**
     * 计算用户关注度分
     */
    private static double calculateUserAttentionScore(int cartCount, BigDecimal price) {
        if (price == null || price.doubleValue() <= 0) {
            return 0.0;
        }
        
        // 加购热度 = 加购人数 ÷ (价格/10)
        double cartHeat = cartCount / (price.doubleValue() / 10.0);
        
        // 用户关注分 = min(100, 加购热度 × 2)
        return Math.min(100, cartHeat * 2.0);
    }
    
    /**
     * 计算社交传播力分
     */
    private static double calculateSocialSpreadScore(List<CommentInfo> comments) {
        if (comments == null || comments.isEmpty()) {
            return 0.0;
        }
        
        Set<String> spreadKeywords = new HashSet<>(Arrays.asList(
                "推荐", "给朋友", "同事", "家人"
        ));
        
        int keywordCount = 0;
        int totalLikes = 0;
        
        for (CommentInfo comment : comments) {
            if (comment.getContent() != null) {
                for (String keyword : spreadKeywords) {
                    if (comment.getContent().contains(keyword)) {
                        keywordCount++;
                        break;
                    }
                }
            }
            if (comment.getLikeCount() != null) {
                totalLikes += comment.getLikeCount();
            }
        }
        
        // 传播关键词分：每个关键词加20分，最高60分
        double keywordScore = Math.min(60, keywordCount * 20);
        
        // 点赞修正 = min(40, 总点赞数 ÷ 5)
        double likeScore = Math.min(40, totalLikes / 5.0);
        
        return keywordScore + likeScore;
    }
    
    /**
     * 计算质量基础评分
     * 质量基础分 = 0.7×初始口碑 + 0.3×产品完成度
     */
    public static double calculateQualityBaseScore(double reputationScore, int commentCount, String description) {
        // 初始口碑（权重70%）
        double initialReputationScore = reputationScore;
        if (commentCount < 5) {
            initialReputationScore = reputationScore * 0.7;
        }
        
        // 产品完成度（权重30%）
        double productCompletenessScore = calculateProductCompletenessScore(description);
        
        return 0.7 * initialReputationScore + 0.3 * productCompletenessScore;
    }
    
    /**
     * 计算产品完成度分
     */
    private static double calculateProductCompletenessScore(String description) {
        if (description == null || description.isEmpty()) {
            return 0.0;
        }
        
        double score = 0.0;
        
        // 有材质描述：+20分
        if (description.contains("材质") || description.contains("面料")) {
            score += 20;
        }
        
        // 有尺寸建议：+20分
        if (description.contains("尺寸") || description.contains("码数")) {
            score += 20;
        }
        
        // 有使用场景：+20分
        if (description.contains("适合") || description.contains("场景")) {
            score += 20;
        }
        
        // 有功能特点：+20分
        if (description.contains("功能") || description.contains("特点")) {
            score += 20;
        }
        
        // 描述详细程度：+20分（根据长度判断）
        if (description.length() > 50) {
            score += 20;
        }
        
        return Math.min(100, score);
    }
    
    /**
     * 计算最终热力值
     * 热力值 = 0.4×新品识别分 + 0.4×热力增长分 + 0.2×质量基础分
     */
    public static double calculateFinalHeatValue(double newProductScore, double heatGrowthScore, 
                                                 double qualityBaseScore, int commentCount) {
        double heatValue = 0.4 * newProductScore + 0.4 * heatGrowthScore + 0.2 * qualityBaseScore;
        
        // 新品保护机制：如果总评论数 < 10
        if (commentCount < 10) {
            heatValue = heatValue * (1 + 0.5 * (10 - commentCount) / 10.0);
        }
        
        return heatValue;
    }
    
    // ==================== 数据类 ====================
    
    @Data
    @Builder
    public static class GoodRateInfo {
        private Double rating;      // 评分
        private Double goodRate;    // 好评率
    }
    
    @Data
    @Builder
    public static class CommentInfo {
        private String content;           // 评论内容
        private LocalDateTime publishDate; // 发布时间
        private Integer likeCount;        // 点赞数
    }
    
    @Data
    @Builder
    public static class ProductFeature {
        private String productId;          // 商品ID
        private String productName;       // 商品名称
        private BigDecimal price;         // 价格
        private String description;      // 描述
        private Double goodRate;          // 好评率
        private Integer cartCount;        // 加购人数
        private Integer returnCustomerCount; // 回头客数
        private List<CommentInfo> comments;  // 评论列表
        private LocalDateTime lastCommentTime; // 最后评论时间
        private String productType; // 产品类型
        private Integer commentCount; // 评论数量（显式设置）

        public int getCommentCount() {
            if (commentCount != null) {
                return commentCount;
            }
            return comments != null ? comments.size() : 0;
        }
    }
    
    @Data
    public static class RecommendationResult {
        private final List<ScoredProduct> products;
        private final double[] entropyWeights;
        private final double[] preferenceWeights;
        
        public RecommendationResult(List<ScoredProduct> products, double[] entropyWeights, double[] preferenceWeights) {
            this.products = products;
            this.entropyWeights = entropyWeights;
            this.preferenceWeights = preferenceWeights;
        }
        
        public static RecommendationResult empty() {
            return new RecommendationResult(Collections.emptyList(), new double[4], new double[4]);
        }
    }
    
    @Data
    public static class UserPreference {
        private double priceWeight;
        private double reputationWeight;
        private double heatWeight;
        private double timelinessWeight;
    }
    
    @Data
    public static class ScoredProduct {
        private final ProductFeature feature;
        private final double priceScore;
        private final double reputationScore;
        private final double heatScore;
        private final double timelinessScore;
        
        @Setter(AccessLevel.PUBLIC)
        private double baseScore;
        
        @Setter(AccessLevel.PUBLIC)
        private double preferenceScore;
        
        @Setter(AccessLevel.PUBLIC)
        private double tagBonus;
        
        @Setter(AccessLevel.PUBLIC)
        private double finalScore;
        
        public ScoredProduct(ProductFeature feature, double priceScore, double reputationScore, double heatScore, double preferenceScore, double timelinessScore) {
            this.feature = feature;
            this.priceScore = priceScore;
            this.reputationScore = reputationScore;
            this.heatScore = heatScore;
            this.preferenceScore = preferenceScore;
            this.timelinessScore = timelinessScore;
        }
    }
}
